package cmpe451.group7.ourcity.dao.impl;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;

import cmpe451.group7.ourcity.dao.CommentDAO;
import cmpe451.group7.ourcity.entity.Comment;
import cmpe451.group7.ourcity.entity.Place;
import cmpe451.group7.ourcity.entity.Tag;
import cmpe451.group7.ourcity.entity.User;
import cmpe451.group7.ourcity.util.TagToMID;
import cmpe451.group7.ourcity.util.Utils;

@Repository("commentDAO")
public class CommentDAOImpl extends GenericDAOImpl<Comment> implements
		CommentDAO, Serializable {

	private static final long serialVersionUID = 1L;

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<Comment> findAll() {
		return super.findAll(Comment.class);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public Comment findByID(long id) {
		return super.findByID(Comment.class, id);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public Comment createComment(Place place, User user, String commentText,
			List<Tag> tags, Date date) {

		Comment comment = new Comment();

		Session session = this.getCurrentSession();

		try {
			comment.setPlace(place);
			comment.setUser(user);
			comment.setDate(date);
			comment.setComment(commentText);

			if (CollectionUtils.isNotEmpty(tags)) {
				for (Tag t : tags) {
					comment.addTag(t);
				}
			}

			session.save(comment);
			//session.flush();

			return comment;
		} catch (Exception e) {
		}

		return null;
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<Comment> findPlaceComments(Place place) {
		Session session = this.getCurrentSession();

		List<Comment> comments = null;
		Criteria criteria = session.createCriteria(Comment.class);
		criteria.addOrder(Order.asc("date"));

		criteria.add(Restrictions.eq("place", place));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		comments = criteria.list();

		return comments;
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<Comment> findPlaceComments(Long placeID) {
		Session session = this.getCurrentSession();

		List<Comment> comments = null;
		Criteria criteria = session.createCriteria(Comment.class);
		criteria.addOrder(Order.asc("date"));

		criteria.add(Restrictions.eq("place.placeID", placeID));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		comments = criteria.list();

		return comments;
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<Comment> findByRestrictions(Long placeID, String comment,
			Date fromDate, Date toDate, List<Tag> tags) {

		Session session = this.getCurrentSession();

		String hql = "select a from Comment a "
				+ ((tags != null) ? "join a.tags t " : "") + "where "
				+ ((tags != null) ? "t.mID in (:tags) and " : "")
				+ "place_placeID like :pn and " + "comment like :cm "
				+ ((fromDate != null) ? "and date >= :fd " : "")
				+ ((toDate != null) ? "and date <= :td " : "") + "group by a "
				+ ((tags != null) ? "having count(t) = :tag_count" : "");

		Query query = session.createQuery(hql);
		query.setParameter("pn", placeID);
		query.setParameter("cm", "%" + comment + "%");

		if (fromDate != null)
			query.setParameter("fd", fromDate);
		if (toDate != null)
			query.setParameter("td", toDate);

		if (tags != null) {
			List<String> tagMIDs = Lists.transform(tags, TagToMID.INSTANCE);
			query.setParameterList("tags", tagMIDs);
			query.setInteger("tag_count", tagMIDs.size());
		}

		List<Comment> comments = query.list();

		return comments;
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public List<Comment> findUserComments(Long userID) {
		Session session = this.getCurrentSession();

		List<Comment> comments = null;
		Criteria criteria = session.createCriteria(Comment.class);
		criteria.addOrder(Order.asc("date"));

		criteria.add(Restrictions.eq("user.userID", userID));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		comments = criteria.list();

		return comments;
	}

}
